﻿using System;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Threading;
using Vtron.ATSP.DomainObjects;
using Vtron.ATSP.Projector.Domain;

namespace Vtron.ATSP.Infrastructure
{
    /// <summary>
    /// Socket 消息处理类
    /// </summary>
    /// <remarks>
    ///     <创建人>邓穗捷</创建人>
    ///     <创建时间>2014-08-14</创建时间>
    ///     <修订人></修订人>
    ///     <修订时间></修订时间>
    ///     <修订说明></修订说明>
    /// </remarks>
    public class SocketHandler : ISocketHandler
    {
        #region Fields

        private int timeOut = 3000;
        private bool IsConnectionSuccessful = false;
        private Exception socketexception;
        private ManualResetEvent TimeoutObject = new ManualResetEvent(false);

        #endregion

        #region Private Helper Methods

        /// <summary>
        /// Socket 连接
        /// </summary>
        /// <param name="ip">Ip</param>
        /// <param name="port">端口号</param>
        /// <param name="timeoutMSec">超时时间(毫秒)</param>
        /// <returns>连接成功后的TCP客户端实体类</returns>
        /// <remarks>
        ///     <创建人>邓穗捷</创建人>
        ///     <创建时间>2014-08-14</创建时间>
        ///     <修订人></修订人>
        ///     <修订时间></修订时间>
        ///     <修订说明></修订说明>
        /// </remarks>
        private TcpClient Connect(string ip, int port, int timeoutMSec)
        {
            TimeoutObject.Reset();
            socketexception = null;
            TcpClient tcpclient = new TcpClient();
            tcpclient.BeginConnect(ip, port, new AsyncCallback(CallBackMethod), tcpclient);
            if (TimeoutObject.WaitOne(timeoutMSec, false))
            {
                if (IsConnectionSuccessful)
                {
                    return tcpclient;
                }
                else
                {
                    throw socketexception;
                }
            }
            else
            {
                tcpclient.Close();
                throw new TimeoutException(String.Format("连接超过指定时间{0}毫秒", timeoutMSec));
            }
        }

        /// <summary>
        /// 回调函数,指示连接成功后的回调操作
        /// </summary>
        /// <param name="asyncresult">异步操作的状态</param>
        /// <remarks>
        ///     <创建人>邓穗捷</创建人>
        ///     <创建时间>2014-08-14</创建时间>
        ///     <修订人></修订人>
        ///     <修订时间></修订时间>
        ///     <修订说明></修订说明>
        /// </remarks>
        private void CallBackMethod(IAsyncResult asyncresult)
        {
            try
            {
                IsConnectionSuccessful = false;
                TcpClient tcpclient = asyncresult.AsyncState as TcpClient;

                if (tcpclient.Client != null)
                {
                    tcpclient.EndConnect(asyncresult);
                    IsConnectionSuccessful = true;
                }
            }
            catch (Exception ex)
            {
                IsConnectionSuccessful = false;
                socketexception = ex;
            }
            finally
            {
                TimeoutObject.Set();
            }
        }

        #endregion

        /// <summary>
        /// Socket 连接
        /// </summary>
        /// <param name="ip">Ip</param>
        /// <param name="port">端口号</param>
        /// <returns>
        /// 是否连接成功:
        ///     true 成功
        ///     flase 失败
        /// </returns>
        /// <remarks>
        ///     <创建人>邓穗捷</创建人>
        ///     <创建时间>2014-08-14</创建时间>
        ///     <修订人></修订人>
        ///     <修订时间></修订时间>
        ///     <修订说明></修订说明>
        /// </remarks>
        public bool Connect(string ip, int port)
        {
            bool result = true;

            try
            {
                TcpClient socket = Connect(ip, port, timeOut);
            }
            catch
            {
                result = false;
            }

            return result;
        }

        /// <summary>
        /// Socket 消息处理
        /// </summary>
        /// <typeparam name="T">应答类型</typeparam>
        /// <param name="request">请求类</param>
        /// <param name="ip">请求Ip</param>
        /// <param name="port">请求端口</param>
        /// <returns>应答类</returns>
        /// <remarks>
        ///     <创建人>邓穗捷</创建人>
        ///     <创建时间>2014-08-14</创建时间>
        ///     <修订人></修订人>
        ///     <修订时间></修订时间>
        ///     <修订说明></修订说明>
        /// </remarks>
        public T Handle<T>(MessageHead request, string ip, int port) where T : MessageHead, new()
        {
            T response = new T();
            byte[] Message = Utils.ObjectToBytes(request);
            TcpClient socket;
            try
            {
                socket = Connect(ip, port, timeOut);
            }
            catch (Exception ex)
            {
                throw new ATSPException(String.Format("连接超时!错误信息:{0}", ex));
            }

            NetworkStream ns = socket.GetStream();
            ns.Write(Message, 0, Message.Length);
            ns.ReadTimeout = 120000;
            byte[] Recv = new byte[1024];
            List<byte> newRecv = new List<byte>();
            try
            {
                do
                {
                    ns.Read(Recv, 0, Recv.Length);
                    newRecv.AddRange(Recv);
                }
                while (ns.DataAvailable);
                byte[] resultRecv = newRecv.ToArray();
                response = (T)Utils.BytesToObject(resultRecv, typeof(T));
            }
            catch (Exception ex)
            {
                throw new ATSPException(String.Format("接收数据出错!错误信息:{0}", ex));
            }
            finally
            {
                socket.Close();
                ns.Close();
            }

            return response;
        }
    }
}